using System;
using System.Collections.Generic;
using System.Linq;
using MT5Trade.Models.MarketData;

namespace MT5Trade.Models
{
    /// <summary>
    /// 赠金套利敞口优化器
    /// 基于凯利公式和GARCH模型优化从账户敞口
    /// </summary>
    public class BonusArbitrageOptimizer
    {
        #region 常量定义

        // 敞口范围约束（基于模型推导）
        private const double MIN_GAP = 0.05;           // 最小敞口5%
        private const double MAX_GAP = 0.25;           // 最大敞口25%
        private const double SAFETY_FACTOR = 0.25;     // 凯利系数的安全因子
        private const double MIN_MARGIN_LEVEL = 1.5;   // 最小保证金水平150%

        // GARCH(1,1)模型参数（基于历史数据估计）
        private const double GARCH_OMEGA = 0.000002;   // 常数项
        private const double GARCH_ALPHA = 0.08;       // ARCH项系数
        private const double GARCH_BETA = 0.90;        // GARCH项系数

        // 风险控制参数
        private const double VAR_CONFIDENCE = 0.95;    // VaR置信水平
        private const double VAR_Z_SCORE = 1.65;       // 95%置信度的Z值
        private const double TARGET_VOLATILITY = 0.015; // 目标波动率1.5%

        #endregion

        #region 核心算法

        /// <summary>
        /// 计算最优套利敞口
        /// 基于凯利公式并考虑多重约束
        /// 时间复杂度：O(1)
        /// 空间复杂度：O(1)
        /// </summary>
        /// <param name="mainLossProbability">主账户预期亏损概率[0.5, 0.85]</param>
        /// <param name="expectedMove">预期波动点数（美元）</param>
        /// <param name="spread">双边点差成本（美元）</param>
        /// <param name="bonusRemaining">剩余赠金金额</param>
        /// <param name="followerMarginLevel">从账户保证金水平（比例）</param>
        /// <param name="currentVolatility">当前市场波动率</param>
        /// <returns>优化后的从账户敞口比例[0.05, 0.25]</returns>
        public double CalculateOptimalGap(
            double mainLossProbability,
            double expectedMove,
            double spread,
            double bonusRemaining,
            double followerMarginLevel,
            double currentVolatility)
        {
            // 输入验证
            ValidateInputs(mainLossProbability, expectedMove, spread,
                          bonusRemaining, followerMarginLevel, currentVolatility);

            // 步骤1：凯利公式计算基础敞口
            // Kelly: f* = (p×b - q) / b
            // 其中：p=主亏概率, q=1-p, b=赔率
            double netReturn = expectedMove - spread;  // 扣除成本后的净收益
            double riskLoss = expectedMove + spread;   // 包含成本的风险损失

            // 防止除零错误
            if (netReturn + riskLoss <= 0)
            {
                return MIN_GAP;
            }

            // 凯利公式推导的最优敞口
            // 修正：对于赠金套利，主账户亏损时从账户盈利
            // 所以公式应该是反向的
            double winProb = mainLossProbability;  // 从账户盈利概率
            double lossProb = 1 - mainLossProbability;  // 从账户亏损概率
            double payoffRatio = netReturn / riskLoss;  // 盈亏比

            // Kelly公式: f* = (p*b - q) / b
            // 其中 p=赢概率, q=输概率, b=盈亏比
            double kellyGap = (winProb * payoffRatio - lossProb) / payoffRatio * SAFETY_FACTOR;

            // 确保Kelly结果为正
            if (kellyGap <= 0)
            {
                kellyGap = MIN_GAP;
            }

            // 步骤2：波动率调整（基于GARCH预测）
            // 高波动降低敞口，低波动增加敞口
            double volatilityAdjustment = CalculateVolatilityAdjustment(currentVolatility);
            kellyGap *= volatilityAdjustment;

            // 步骤3：赠金剩余量调整
            // 赠金即将耗尽时增加敞口，加速套利
            double bonusAdjustment = CalculateBonusAdjustment(bonusRemaining);
            kellyGap *= bonusAdjustment;

            // 步骤4：保证金水平约束
            // 保护从账户避免爆仓
            double marginAdjustment = CalculateMarginAdjustment(followerMarginLevel);
            kellyGap *= marginAdjustment;

            // 步骤5：边界约束
            return Math.Max(MIN_GAP, Math.Min(MAX_GAP, kellyGap));
        }

        /// <summary>
        /// 使用GARCH(1,1)模型预测下一期波动率
        /// σ²_t = ω + α×ε²_{t-1} + β×σ²_{t-1}
        /// 时间复杂度：O(1)
        /// </summary>
        public double PredictVolatility(double currentReturn, double currentVolatility)
        {
            // GARCH(1,1)方程
            double nextVariance = GARCH_OMEGA +
                                 GARCH_ALPHA * Math.Pow(currentReturn, 2) +
                                 GARCH_BETA * Math.Pow(currentVolatility, 2);

            // 确保非负性
            nextVariance = Math.Max(0.000001, nextVariance);

            return Math.Sqrt(nextVariance);
        }

        /// <summary>
        /// 计算95% VaR动态止损位
        /// VaR_95 = -μ + Z_α × σ × √Δt × Position_Value
        /// 时间复杂度：O(1)
        /// </summary>
        public double CalculateVarStopLoss(
            double entryPrice,
            double accountEquity,
            double positionSize,
            double volatility,
            double expectedReturn = 0)
        {
            // 日波动率转换为单位时间波动率（假设252交易日）
            double timeAdjustedVolatility = volatility * Math.Sqrt(1.0 / 252);

            // 95% VaR计算
            double var95 = VAR_Z_SCORE * timeAdjustedVolatility * positionSize * entryPrice;

            // 考虑期望收益的调整
            var95 -= expectedReturn * positionSize * entryPrice;

            // 动态止损价格（不能让损失超过账户净值的特定比例）
            double maxAcceptableLoss = accountEquity * 0.05;  // 最大可接受5%损失
            var95 = Math.Min(var95, maxAcceptableLoss);

            double stopLoss = entryPrice * (1 - var95 / (positionSize * entryPrice));

            return Math.Max(0, stopLoss);  // 确保止损价格非负
        }

        /// <summary>
        /// 评估套利机会质量
        /// 综合技术指标给出主账户亏损概率
        /// 时间复杂度：O(1)
        /// </summary>
        public ArbitrageSignal EvaluateOpportunity(MarketCondition condition)
        {
            if (condition == null)
            {
                throw new ArgumentNullException(nameof(condition));
            }

            var signal = new ArbitrageSignal();

            // 技术指标综合评分（0-1）
            double score = 0;

            // 1. 阻力/支撑强度评估（权重40%）
            if (condition.IsAtStrongResistance && condition.IsBullish)
            {
                score += 0.4;  // 在强阻力做多，高概率失败
            }
            else if (condition.IsAtStrongSupport && !condition.IsBullish)
            {
                score += 0.4;  // 在强支撑做空，高概率失败
            }

            // 2. 超买/超卖评估（权重30%）
            if (condition.RSI > 70)
            {
                score += 0.3 * (condition.RSI - 70) / 30;  // 超买程度
            }
            else if (condition.RSI < 30)
            {
                score += 0.3 * (30 - condition.RSI) / 30;  // 超卖程度
            }

            // 3. 趋势衰竭评估（权重30%）
            score += 0.3 * condition.TrendExhaustion;

            // 计算主账户预期亏损概率
            // 基础50% + 技术评分调整（最高可达85%）
            signal.MainLossProbability = 0.5 + score * 0.35;
            signal.Quality = score;

            // 计算建议敞口
            signal.RecommendedGap = CalculateOptimalGap(
                signal.MainLossProbability,
                condition.ExpectedMove,
                condition.Spread,
                condition.BonusRemaining,
                condition.FollowerMarginLevel,
                condition.Volatility
            );

            // 设置信号有效性
            signal.IsValid = score >= 0.5;  // 质量评分超过50%才有效
            signal.Timestamp = DateTime.Now;

            return signal;
        }

        #endregion

        #region 辅助方法

        /// <summary>
        /// 波动率调整系数计算
        /// </summary>
        private double CalculateVolatilityAdjustment(double volatility)
        {
            // 使用指数函数平滑调整
            // 当波动率高于目标时，降低敞口
            // 当波动率低于目标时，增加敞口
            double adjustment = Math.Exp(-2.0 * (volatility - TARGET_VOLATILITY));

            // 限制调整范围[0.5, 1.5]
            return Math.Max(0.5, Math.Min(1.5, adjustment));
        }

        /// <summary>
        /// 赠金剩余量调整系数计算
        /// </summary>
        private double CalculateBonusAdjustment(double bonusRemaining)
        {
            const double INITIAL_BONUS = 500.0;
            double utilizationRate = bonusRemaining / INITIAL_BONUS;

            if (utilizationRate < 0.2)  // 赠金剩余不足20%
            {
                return 1.5;  // 增加50%敞口，加速套利
            }
            else if (utilizationRate < 0.3)  // 赠金剩余不足30%
            {
                return 1.3;  // 增加30%敞口
            }
            else if (utilizationRate > 0.8)  // 赠金充足
            {
                return 0.9;  // 略微降低敞口，保守策略
            }

            return 1.0;  // 标准敞口
        }

        /// <summary>
        /// 保证金水平调整系数计算
        /// </summary>
        private double CalculateMarginAdjustment(double marginLevel)
        {
            if (marginLevel < MIN_MARGIN_LEVEL)  // 低于150%
            {
                // 线性降低敞口
                return marginLevel / MIN_MARGIN_LEVEL;
            }
            else if (marginLevel < 2.0)  // 150%-200%
            {
                // 轻微降低
                return 0.9 + 0.1 * (marginLevel - MIN_MARGIN_LEVEL) / 0.5;
            }

            return 1.0;  // 保证金充足，不调整
        }

        /// <summary>
        /// 输入参数验证
        /// </summary>
        private void ValidateInputs(
            double mainLossProbability,
            double expectedMove,
            double spread,
            double bonusRemaining,
            double followerMarginLevel,
            double currentVolatility)
        {
            if (mainLossProbability < 0 || mainLossProbability > 1)
                throw new ArgumentException("主账户亏损概率必须在[0,1]范围内");

            if (expectedMove <= 0)
                throw new ArgumentException("预期波动必须为正数");

            if (spread < 0)
                throw new ArgumentException("点差不能为负数");

            if (bonusRemaining < 0)
                throw new ArgumentException("剩余赠金不能为负数");

            if (followerMarginLevel <= 0)
                throw new ArgumentException("保证金水平必须为正数");

            if (currentVolatility < 0)
                throw new ArgumentException("波动率不能为负数");
        }

        #endregion

        #region 新增方法 - GARCH和VaR计算

        /// <summary>
        /// 使用GARCH(1,1)模型预测波动率
        /// σ²_t = ω + α×ε²_{t-1} + β×σ²_{t-1}
        /// 时间复杂度: O(n) where n = returns.Length
        /// 空间复杂度: O(1)
        /// </summary>
        public double PredictVolatilityGARCH(double[] returns, double omega, double alpha, double beta)
        {
            if (returns == null || returns.Length == 0)
                return 0.015; // 默认波动率 1.5%

            // 验证GARCH参数约束
            if (alpha < 0 || beta < 0 || alpha + beta >= 1)
            {
                // 使用默认参数
                omega = 0.00001;
                alpha = 0.05;
                beta = 0.94;
            }

            // 初始化条件方差
            double variance = omega / (1 - alpha - beta); // 长期方差

            // 迭代计算GARCH方差
            foreach (var r in returns)
            {
                variance = omega + alpha * r * r + beta * variance;
            }

            return Math.Sqrt(variance);
        }

        /// <summary>
        /// 计算Value at Risk (VaR)
        /// 使用历史模拟法
        /// 时间复杂度: O(n log n) due to sorting
        /// 空间复杂度: O(n)
        /// </summary>
        public double CalculateVaR(double[] returns, double confidenceLevel)
        {
            if (returns == null || returns.Length == 0)
                return 0.05; // 默认VaR 5%

            // 验证置信水平
            if (confidenceLevel <= 0 || confidenceLevel >= 1)
                confidenceLevel = 0.95; // 默认95%置信水平

            // 复制数组避免修改原始数据
            var sortedReturns = new double[returns.Length];
            Array.Copy(returns, sortedReturns, returns.Length);
            Array.Sort(sortedReturns);

            // 计算VaR分位数位置
            int index = (int)((1 - confidenceLevel) * sortedReturns.Length);
            index = Math.Max(0, Math.Min(index, sortedReturns.Length - 1));

            return Math.Abs(sortedReturns[index]);
        }

        /// <summary>
        /// 计算基于VaR的止损价格
        /// 时间复杂度: O(1)
        /// 空间复杂度: O(1)
        /// </summary>
        public double CalculateVarStopLoss(double entryPrice, double accountEquity,
                                           double positionSize, double volatility)
        {
            // 输入验证
            if (entryPrice <= 0 || accountEquity <= 0 || positionSize <= 0)
                throw new ArgumentException("价格、账户净值和仓位必须为正数");

            // 最大风险设置（账户净值的2%）
            const double maxRiskPercentage = 0.02;
            double maxRisk = accountEquity * maxRiskPercentage;

            // 基于波动率调整
            double volatilityMultiplier = Math.Max(1.0, volatility / 0.015); // 相对于1.5%基准波动率

            // 计算止损距离
            double stopDistance = (maxRisk / positionSize) / volatilityMultiplier;

            // 止损价格（做多情况）
            double stopLoss = entryPrice - stopDistance;

            // 确保止损价格合理（不低于入场价的90%）
            stopLoss = Math.Max(stopLoss, entryPrice * 0.9);

            return stopLoss;
        }

        #endregion
    }

    /// <summary>
    /// 市场条件数据结构
    /// </summary>
    public class MarketCondition
    {
        public bool IsAtStrongResistance { get; set; }
        public bool IsAtStrongSupport { get; set; }
        public bool IsBullish { get; set; }
        public double RSI { get; set; }
        public double TrendExhaustion { get; set; }
        public double ExpectedMove { get; set; }
        public double Spread { get; set; }
        public double BonusRemaining { get; set; }
        public double FollowerMarginLevel { get; set; }
        public double Volatility { get; set; }
    }

    /// <summary>
    /// 套利信号
    /// </summary>
    public class ArbitrageSignal
    {
        public double Quality { get; set; }              // 机会质量评分[0,1]
        public double MainLossProbability { get; set; }  // 主账户预期亏损概率
        public double RecommendedGap { get; set; }       // 建议敞口
        public bool IsValid { get; set; }                // 信号是否有效
        public DateTime Timestamp { get; set; }          // 信号生成时间
    }

    /// <summary>
    /// 动态敞口调整器
    /// 基于近期交易表现动态优化敞口
    /// </summary>
    public class DynamicGapAdjuster
    {
        private readonly Queue<bool> _recentResults = new Queue<bool>(20);
        private double _lastAdjustmentTime = 0;
        private readonly object _lockObj = new object();

        /// <summary>
        /// 基于近期表现动态调整敞口
        /// 时间复杂度：O(n)，n=lookback period (20)
        /// </summary>
        public double AdjustForRecentPerformance(
            double baseGap,
            bool isWin,
            double timestamp)
        {
            lock (_lockObj)
            {
                // 更新历史记录
                _recentResults.Enqueue(isWin);
                if (_recentResults.Count > 20)
                {
                    _recentResults.Dequeue();
                }

                // 即使历史数据较少，也进行基本调整
                if (_recentResults.Count < 3)
                {
                    // 简单调整：亏损增加5%，盈利减少5%
                    return isWin ? baseGap * 0.95 : baseGap * 1.05;
                }

                // 计算实际胜率
                double actualWinRate = _recentResults.Count(r => r) / (double)_recentResults.Count;

                // 计算连续亏损
                int consecutiveLosses = 0;
                foreach (var result in _recentResults.Reverse())
                {
                    if (!result) consecutiveLosses++;
                    else break;
                }

                // 动态调整因子
                double adjustmentFactor = 1.0;

                // 1. 基于实际胜率调整
                if (actualWinRate < 0.35)  // 严重低于预期
                {
                    adjustmentFactor *= 1.4;  // 大幅增加敞口补偿
                }
                else if (actualWinRate < 0.45)  // 低于预期
                {
                    adjustmentFactor *= 1.2;  // 中度增加敞口
                }
                else if (actualWinRate > 0.75)  // 远高于预期
                {
                    adjustmentFactor *= 0.7;  // 降低敞口，锁定利润
                }
                else if (actualWinRate > 0.65)  // 高于预期
                {
                    adjustmentFactor *= 0.85;  // 略微降低敞口
                }

                // 2. 连续亏损保护机制
                if (consecutiveLosses >= 5)
                {
                    adjustmentFactor *= 1.5;  // 连续5次，大幅增加
                }
                else if (consecutiveLosses >= 3)
                {
                    adjustmentFactor *= 1.25;  // 连续3次，中度增加
                }

                // 3. 时间衰减（防止过度调整）
                double timeSinceLastAdjustment = timestamp - _lastAdjustmentTime;
                if (timeSinceLastAdjustment < 3600)  // 1小时内
                {
                    // 线性衰减调整强度
                    double decayFactor = timeSinceLastAdjustment / 3600;
                    adjustmentFactor = 1.0 + (adjustmentFactor - 1.0) * decayFactor;
                }

                _lastAdjustmentTime = timestamp;

                // 应用调整并确保在合理范围内
                double adjustedGap = baseGap * adjustmentFactor;
                return Math.Max(0.05, Math.Min(0.25, adjustedGap));
            }
        }

        /// <summary>
        /// 重置历史记录
        /// </summary>
        public void Reset()
        {
            lock (_lockObj)
            {
                _recentResults.Clear();
                _lastAdjustmentTime = 0;
            }
        }

        /// <summary>
        /// 获取当前统计信息
        /// </summary>
        public (double winRate, int consecutiveLosses, int sampleSize) GetStatistics()
        {
            lock (_lockObj)
            {
                if (_recentResults.Count == 0)
                    return (0.5, 0, 0);

                double winRate = _recentResults.Count(r => r) / (double)_recentResults.Count;

                int consecutiveLosses = 0;
                foreach (var result in _recentResults.Reverse())
                {
                    if (!result) consecutiveLosses++;
                    else break;
                }

                return (winRate, consecutiveLosses, _recentResults.Count);
            }
        }
    }
}